package game;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Random;

public class GameField {

	private ArrayList<Zombie> zombies = new ArrayList<Zombie>();
	private ArrayList<Bullet> bullets = new ArrayList<Bullet>();

	private int[][] field;
	private double[][] smell;
	Random r = new Random();

	public final int sx = 25;
	public final int sy = 25;

	public final int bsize = 25;

	private int score = 0;

	double phealth = 100;
	double halpha = 0;

	private BufferedImage blood = new BufferedImage((bsize * sx) / 2,
			(bsize * sy) / 2, BufferedImage.TYPE_INT_RGB);

	public int playerx = 10;
	public int playery = 10;

	private double px;
	private double py;

	public double mousex;
	public double mousey;

	private double pvx;
	private double pvy;

	public boolean[] k = new boolean[32767];
	public boolean shooting = false;

	public GameField() {
		for (int x = 0; x < (bsize * sx) / 2; x++) {
			for (int y = 0; y < (bsize * sx) / 2; y++) {
				blood.setRGB(x, y, Color.WHITE.getRGB());
			}
		}
		field = new int[sx][sy];
		smell = new double[sx][sy];
		generateField();
		field[10][10] = 4;
		// for (int q = 0; q < 520; q++) {
		// double xx = r.nextDouble() * bsize * sx;
		// double yy = r.nextDouble() * bsize * sy;
		// if (field[(int) (xx / bsize)][(int) (yy / bsize)] > 1)
		// zombies.add(new Zombie(xx, yy, this));
		// }
		calcSmell(playery, playerx, 100);
		px = 10 * bsize;
		py = 10 * bsize;
	}

	public void loadFromFile(String filename) {
		// TODO
	}

	public void generateField() {
		for (int x = 0; x < sx; x++) {
			for (int y = 0; y < sy; y++) {
				field[x][y] = r.nextInt(12) + 5;
				smell[x][y] = 0;
				if (x == 0 || x == sx - 1)
					field[x][y] = 1;
				if (y == 0 || y == sy - 1)
					field[x][y] = 1;
			}
		}
	}

	public void calcSmell() {
		for (int x = 0; x < sx; x++) {
			for (int y = 0; y < sy; y++) {
				smell[x][y] = 0;
			}
		}
		calcSmell(playerx, playery, 100);
	}

	public void calcSmell(int x, int y, double s) {
		if (x < 0 || x >= sx || y < 0 || y >= sy)
			return;
		if (smell[x][y] >= s)
			return;
		if (field[x][y] <= 1)
			return;
		smell[x][y] = s;

		calcSmell(x + 1, y, s * 0.9);
		calcSmell(x - 1, y, s * 0.9);
		calcSmell(x, y - 1, s * 0.9);
		calcSmell(x, y + 1, s * 0.9);
	}

	public int read(int x, int y) {
		if (x < 0 || x >= sx || y < 0 || y >= sy)
			return 0;
		return field[x][y];
	}

	public void movePlayer(double d, double y) {
		pvx += d;
		pvy += y;

	}

	public double readSmell(int x, int y) {
		if (x < 0 || x >= sx || y < 0 || y >= sy)
			return 0;
		return smell[x][y];
	}

	private void runPlayer() {
		if (px + pvx < 0 || px + pvx > sx * bsize)
			pvx *= -0.1;
		if (py + pvy < 0 || py + pvy > sy * bsize)
			pvy *= -0.1;

		if (read((int) ((px + pvx) / bsize), (int) (py / bsize)) <= 1) {
			pvx *= -0.1;
		}
		if (read((int) ((px) / bsize), (int) ((py + pvy) / bsize)) <= 1) {
			pvy *= -0.1;
		}

		pvx *= 0.95;
		pvy *= 0.95;

		px += pvx;
		py += pvy;

	}

	public void addBullet(double mx, double my) {

		double dx = (mx - px) / 10 + Math.random();
		double dy = (my - py) / 10 + Math.random();
		double Norm = 1 / (Math.sqrt((dx) * (dx) + (dy) * (dy)));
		dx *= Norm * 5;
		dy *= Norm * 5;
		bullets.add(new Bullet(dx, dy, px, py));
	}

	public void run() {
		if(halpha > 0)
			halpha *= 0.995;
		double mx = 0;
		double my = 0;
		if (k[KeyEvent.VK_W])
			my -= 0.25;
		if (k[KeyEvent.VK_A])
			mx -= 0.25;
		if (k[KeyEvent.VK_S])
			my += 0.25;
		if (k[KeyEvent.VK_D])
			mx += 0.25;
		movePlayer(mx, my);

		if (shooting && System.currentTimeMillis() % 1 == 0) {
			addBullet(mousex, mousey);
		}

		runPlayer();
		if (playerx != (int) px / bsize || playery != (int) py / bsize) {
			playerx = (int) (px / bsize);
			playery = (int) (py / bsize);
			calcSmell();
		}
		playerx = (int) (px / bsize);
		playery = (int) (py / bsize);
		for(int i = 0;i < 10;i++){
		if (Math.random() > 0.2 && zombies.size() < 100) {
			for (int a = 0; a < 1; a++) {
				double xx = r.nextDouble() * bsize * sx;
				double yy = r.nextDouble() * bsize * sy;
				if (smell[(int) (xx / bsize)][(int) (yy / bsize)] < 50)
					zombies.add(new Zombie(xx, yy, this));
			}
		}
		}
		ArrayList<Zombie> remObjects = new ArrayList<Zombie>();
		ArrayList<Bullet> remBullets = new ArrayList<Bullet>();
		for (Bullet bullet : bullets) {
			bullet.run();
			for (Zombie object : zombies) {
				if (Math.abs(bullet.x - object.x) < 5
						&& (Math.abs(bullet.y - object.y) < 5)) {
					blood((int) object.px + bsize, (int) object.py + bsize, 20,
							50, 0.1);
					object.health -= 30;
					remBullets.add(bullet);
				}
			}
			if (field[(int) (bullet.x / bsize)][(int) (bullet.y / bsize)] <= 1)
				remBullets.add(bullet);
		}

		for (Bullet bullet : remBullets) {
			bullets.remove(bullet);
		}

		for (Zombie object : zombies) {
			// if (object.x / bsize == playerx && object.y / bsize == playery)
			// remObjects.add(object);
			object.run();
			int zx = (int) (object.px + bsize / 2) / 2;
			int zy = (int) (object.py + bsize / 2) / 2;

			if (Math.abs(object.px - px) < 25 && Math.abs(object.py - py) < 25) {
				object.vx -= (object.px - px) * 0.002;
				object.vy -= (object.py - py) * 0.002;
			}

			if (Math.abs(object.px - px) < 3 && Math.abs(object.py - py) < 3) {
				phealth -= 0.1;
				halpha += 0.1;
			}

			int zvx = (int) ((object.px - object.vx * 3) + bsize / 2) / 2;
			int zvy = (int) ((object.py - object.vy * 3) + bsize / 2) / 2;

			if (zx < (bsize * sx) / 2 && zy < (bsize * sy) / 2 && zx > 0
					&& zy > 0) {

				if (new Color(blood.getRGB(zx, zy)).getBlue() < 140) {
					object.bloodie += 0.1;
					cleanup(zvx * 2, zvy * 2, 5, 10);
				}
				if (object.bloodie > 0) {
					if (object.bloodie > 1)
						object.bloodie = 1;
					blood(zx * 2, zy * 2, 5, 10, 1 - object.bloodie);

				}
				if (object.health < 0)
					remObjects.add(object);
			}
			for (Zombie object2 : zombies) {
				if (object == object2)
					break;
				object.collide(object2);
			}

		}

		for (Zombie object : remObjects) {
			blood((int) object.px + bsize, (int) object.py + bsize, 8, 20, 0.4);
			zombies.remove(object);
			score++;

		}

	}

	public void cleanup(int x, int y, int size, int amount) {

		for (int q = 0; q < amount; q++) {
			int rx = (x / 2) - size + r.nextInt(size / 2);
			int ry = (y / 2) - size + r.nextInt(size / 2);
			if (rx < (bsize * sx) / 2 && ry < (bsize * sy) / 2 && rx > 0
					&& ry > 0) {
				Color c = new Color(blood.getRGB(rx, ry));
				Color b = new Color((int) ((c.getRed() * 0.7) + (255 * 0.3)),
						(int) ((c.getGreen() * 0.7 + 255 * 0.3)),
						(int) ((c.getGreen() * 0.7 + 255 * 0.3)));
				blood.setRGB(rx, ry, b.getRGB());

			}
		}

	}

	public void blood(int x, int y, int size, int amount, double dens) {
		x = x - bsize / 2;
		y = y - bsize / 2;
		for (int q = 0; q < amount; q++) {
			int rx = (x / 2) - size / 2 + r.nextInt(size);
			int ry = (y / 2) - size / 2 + r.nextInt(size);
			if (rx < (bsize * sx) / 2 && ry < (bsize * sy) / 2 && rx > 0
					&& ry > 0) {
				Color c = new Color(blood.getRGB(rx, ry));
				double b = dens;
				blood.setRGB(
						rx,
						ry,
						new Color(
								(int) ((c.getRed() * (b)) + ((double) (250 - (double) r
										.nextInt(150)) * (1 - b))),
								(int) ((double) c.getGreen() * (b)),
								(int) ((double) c.getBlue() * (b))).getRGB());
			}
		}
	}

	public void draw(Graphics g) {

		Graphics2D g2 = (Graphics2D) g;
		float alpha = 1.0f;
		g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
				alpha));
		g.drawImage(blood, 0, 0, 625, 625, new Color(255, 255, 255, 255), null);
		g.setColor(Color.RED);
		g.fillOval((int) px, (int) py, 5, 5);

		for (Zombie object : zombies) {
			object.draw(g);
		}
		g.setColor(Color.BLACK);
		for (int x = 0; x < sx; x++) {
			for (int y = 0; y < sy; y++) {
				// if(smell[x][y] >= 80){
				alpha = (float) (((1 - (float) ((smell[x][y]) / 100))));
				if (alpha > 1)
					alpha = 1;
				g2.setComposite(AlphaComposite.getInstance(
						AlphaComposite.SRC_OVER, alpha));
				g2.fillRect(x * bsize, y * bsize, bsize, bsize);
			}
		}

		for (Bullet bullet : bullets) {
			
			bullet.draw(g2);
		}
		g.setColor(Color.RED);
		if(halpha > 0.9)
			halpha = 0.9;
		alpha = (float) halpha;
		g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
				alpha));
		g2.fillRect(0, 0, (bsize * sx), (bsize * sy));
		g.setColor(Color.RED);
		alpha = 1.0f;
		g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
				alpha));
		g.drawString("Score: " + score, 10, 10);
		g.drawString("Health: " + ((int)phealth), 10, 30);

	}
}
